import { Router } from 'express';
import { body } from 'express-validator';
import utils from '../helpers/utils.js';
import uploader from '../helpers/uploader.js';
import Rbac from '../helpers/rbac.js';
import validateFormData from '../helpers/validate_form.js';
import DB from '../models/db.js';
import Web3 from 'web3';
import { Op } from 'sequelize';
const router = Router();
const web3 = new Web3();
/**
 * Route to view user account record
 * @GET /account
 */
router.get(['/','/index'], async (req, res) => {
	try{
		let recid = req.user.user_id;
		let query = {};
		let where = {};
		where['user_id'] = recid;
		query.raw = true;
		query.where = where;
		query.attributes = DB.Users.accountviewFields();
		let record = await DB.Users.findOne(query);
		if(!record){
			return res.notFound();
		}
		return res.ok(record);
	}
	catch(err){
		return res.serverError(err);
	}
});
/**
 * Route to get  Users record for edit
 * @GET /users/edit/{recid}
 */
router.get(['/edit'], async (req, res) => {
	try{
		const recid = req.user.user_id;
		const query = {};
		const where = {};
		where['user_id'] = recid;
		query.raw = true;
		query.where = where;
		query.attributes = DB.Users.accounteditFields();
		let record = await DB.Users.findOne(query);
		if(!record){
			return res.notFound();
		}
		return res.ok(record);
	}
	catch(err){
		return res.serverError(err);
	}
});
/**
 * Route to update  Users record
 * @POST /users/edit/{recid}
 */
router.post(['/edit'], 
	[
		body('username').optional({nullable: true}).not().isEmpty(),
		body('name').optional({nullable: true}).not().isEmpty(),
		body('personnel_id').optional({nullable: true, checkFalsy: true}),
		body('phone_number').optional({nullable: true, checkFalsy: true}),
		body('avatar_url').optional({nullable: true, checkFalsy: true}),
	], validateFormData
, async (req, res) => {
	try{
		const recid = req.user.user_id;
		let modeldata = req.getValidFormData({ includeOptionals: true });
        // move uploaded file from temp directory to destination directory
		if(modeldata.avatar_url !== undefined) {
			const fileInfo = uploader.moveUploadedFiles(modeldata.avatar_url, 'avatar_url');
			modeldata.avatar_url = fileInfo.filepath;
		}
		const query = {};
		const where = {};
		where['user_id'] = recid;
		query.raw = true;
		query.where = where;
		query.attributes = DB.Users.accounteditFields();
		let record = await DB.Users.findOne(query);
		if(!record){
			return res.notFound();
		}
		const oldValues = JSON.stringify(record); //for audit trail
		await DB.Users.update(modeldata, {where: where});
		record = await DB.Users.findOne(query);//for audit trail
		const newValues = JSON.stringify(record); 
		req.writeToAuditLog({ recid, oldValues, newValues });
		return res.ok(modeldata);
	}
	catch(err){
		return res.serverError(err);
	}
});
router.get('/currentuserdata', async function (req, res)
{
	const user = req.user;
	const userRole = user.user_role_id;
	const rbac = new Rbac(userRole);
	const pages = await rbac.getUserPages();
	const roles = await rbac.getRoleName();
    return res.ok({ user, pages, roles });
});
/**
 * Route to change user password
 * @POST /account
 */
router.post('/changepassword' , 
	[
		body('oldpassword').not().isEmpty(),
		body('newpassword').not().isEmpty(),
		body('confirmpassword').not().isEmpty().custom((value, {req}) => (value === req.body.newpassword))
	], validateFormData, async function (req, res) {
	try{
		let oldPassword = req.body.oldpassword;
		let newPassword = req.body.newpassword;
		let userId = req.user.user_id;
		let query = {};
		let where = {
			user_id: userId,
		};
		query.raw = true;
		query.where = where;
		query.attributes = ['password'];
		let user = await DB.Users.findOne(query);
		let currentPasswordHash = user.password;
		if(!utils.passwordVerify(oldPassword, currentPasswordHash)){
			return res.badRequest("Current password is incorrect");
		}
		let modeldata = {
			password: utils.passwordHash(newPassword)
		}
		await DB.Users.update(modeldata, {where: where});
		return res.ok("Password change completed");
	}
	catch(err){
		return res.serverError(err);
	}
});
/**
 * Route to get user's ethereum account info
 * @GET /account/ethereum
 */
router.get('/ethereum', async (req, res) => {
    try {
        const userId = req.user.user_id;
        const query = {
            raw: true,
            where: { user_id: userId },
            attributes: ['ethereum_address']
        };
        const record = await DB.Users.findOne(query);
        if (!record) {
            return res.notFound();
        }
        return res.ok(record);
    }
    catch (err) {
        return res.serverError(err);
    }
});
/**
 * Route to bind ethereum account
 * @POST /account/ethereum/bind
 */
router.post('/ethereum/bind', 
    [
        body('ethereum_address').not().isEmpty().custom((value) => {
            if (!Web3.utils.isAddress(value)) {
                throw new Error('Invalid Ethereum address');
            }
            return true;
        }),
        body('signature').not().isEmpty().custom((value) => {
            if (!value.startsWith('0x') || value.length !== 132) {
                throw new Error('Invalid signature format');
            }
            return true;
        }),
    ], 
    validateFormData,
    async (req, res) => {
        try {
            const userId = req.user.user_id;
            const { ethereum_address, signature } = req.body;

            // 检查地址是否已经被其他用户绑定
            const existingUser = await DB.Users.findOne({
                where: { 
                    ethereum_address: ethereum_address,
                    user_id: { [Op.ne]: userId } // 排除当前用户
                }
            });
            if (existingUser) {
                return res.badRequest("This Ethereum address is already bound to another account");
            }

            // Verify signature
            const message = `Bind Ethereum account ${ethereum_address} to user ${userId}`.trim();
            console.log('Verifying signature for message:', message);
            console.log('Signature:', signature);
            
            try {
                // 直接使用消息和签名进行验证
                const signer = web3.eth.accounts.recover(message, signature);
                console.log('Recovered signer:', signer);
                console.log('Expected address:', ethereum_address);
                
                if (signer.toLowerCase() !== ethereum_address.toLowerCase()) {
                    console.log('Signature verification failed');
                    return res.badRequest("Invalid signature");
                }
            } catch (err) {
                console.error('Signature verification error:', err);
                return res.badRequest("Invalid signature format");
            }

            const query = {
                where: { user_id: userId }
            };
            const modeldata = {
                ethereum_address: ethereum_address
            };

            await DB.Users.update(modeldata, query);
            return res.ok({ message: "Ethereum account bound successfully" });
        }
        catch (err) {
            console.error('Error binding Ethereum account:', err);
            return res.serverError(err);
        }
    }
);
export default router;
